using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using Kaleta.Xna;
using Kaleta.Xna.Collision;
using Kaleta.Network;
using System.Xml.Serialization;
using System.IO;
using Kaleta.Xna.Distributed;
using Kaleta.Xna.Timing;
using Kaleta.Xna.Animators;
using Kaleta.Xna.Extensions;


namespace Kaleta.Xna.Tester
{
    public static class DebuggerView
    {
        static Dictionary<string, object> values = new Dictionary<string, object>();
        static float TextScale = 0.7f;

        static public void SetValue(string key, object value)
        {
            if (!values.ContainsKey(key))
                values.Add(key, value);
            else
                values[key] = value;
        }

        static public T GetValue<T>(string key)
        {
            if (!values.ContainsKey(key))
                values.Add(key, default(T));

            return (T)values[key];
        }


        static public void Draw(SpriteBatch spriteBatch)
        {
            int i = 0;
            foreach (var kvp in values)
            {
                spriteBatch.DrawString(
                    Game1.font, kvp.Key + ":" + kvp.Value.ToString(), new Vector2(10, i * 30), Color.White, 0.0f, Vector2.Zero, TextScale, SpriteEffects.None, 0);

                i++;
            }
        }



    }

    public class Shield
    {
        protected int frame;
        protected int frameCountSqrt;

        public Vector2 Scale { get; set; }
        public Vector2 Origin { get; set; }
        private Ship owner;

        public Shield(Ship owner)
        {
            this.owner = owner;
            this.Scale = new Vector2()
            {
                X = 1.25f * (float)(this.owner.Texture.Width * this.owner.Body.Scale.X) / (Global.SpriteSheets.Shield1.FrameWidht),
                Y = 1.25f * (float)(this.owner.Texture.Height * this.owner.Body.Scale.Y) / (Global.SpriteSheets.Shield1.FrameHeight),
            };


            frameCountSqrt = (int)Math.Sqrt(Global.SpriteSheets.Shield1.FrameCount);
            frame = -1;
            this.Origin = new Vector2()
            {
                X = Global.SpriteSheets.Shield1.FrameWidht / 2,
                Y = Global.SpriteSheets.Shield1.FrameHeight / 2
            };
            Game1.shields.Add(this);
        }

        public void Update(GameTime gameTime)
        {
            frame = (frame + 1);
            if (frame == Global.SpriteSheets.Shield1.FrameCount)
                Game1.shieldsToRemove.Add(this);

        }

        public void Draw(SpriteBatch batch)
        {
            int x = frame % frameCountSqrt;
            int y = frame / frameCountSqrt;

            batch.Draw(Global.SpriteSheets.Shield1.Texture, this.owner.Position,
                new Rectangle(x * Global.SpriteSheets.Shield1.FrameWidht, y * Global.SpriteSheets.Shield1.FrameHeight, Global.SpriteSheets.Shield1.FrameWidht, Global.SpriteSheets.Shield1.FrameHeight),
                Color.White,
                    this.owner.Direction, this.Origin, this.Scale, SpriteEffects.None, 0.0f);
        }
    }


    public class Explosion
    {
        protected int frame;
        protected int frameCountSqrt;

        public Vector2 Position { get; set; }
        public float Scale { get; set; }
        public float Direction { get; set; }
        public Vector2 Velocity { get; set; }
        public Vector2 Origin { get; set; }


        public Explosion(Vector2 position, Vector2 velocity)
        {

            frameCountSqrt = (int)Math.Sqrt(Global.SpriteSheets.ShieldExplosion1.FrameCount);
            Scale = 0.5f;
            Origin = new Vector2(Global.SpriteSheets.ShieldExplosion1.FrameWidht / 2.0f, Global.SpriteSheets.ShieldExplosion1.FrameHeight / 2.0f);
            Direction = 0;
            Position = position;
            Velocity = velocity;
            frame = -1;

            Game1.explosions.Add(this);
        }

        public void Update(GameTime gameTime)
        {
            frame = (frame + 1);
            if (frame == Global.SpriteSheets.ShieldExplosion1.FrameCount)
                Game1.explosionsToRemove.Add(this);

        }

        public void Draw(SpriteBatch batch)
        {
            int x = frame % frameCountSqrt;
            int y = frame / frameCountSqrt;

            Position = new Vector2() { X = Position.X + Velocity.X, Y = Position.Y + Velocity.Y };

            batch.Draw(Global.SpriteSheets.ShieldExplosion1.Texture, this.Position,
                new Rectangle(x * Global.SpriteSheets.ShieldExplosion1.FrameWidht, y * Global.SpriteSheets.ShieldExplosion1.FrameHeight, Global.SpriteSheets.ShieldExplosion1.FrameWidht, Global.SpriteSheets.ShieldExplosion1.FrameHeight),
                Color.White,
                    this.Direction, this.Origin, this.Scale, SpriteEffects.None, 0.0f);
        }
    }

    [Flags]
    public enum ShipState
    {
        Accelerating = 1,
        Breaking = 2,
        RotatingLeft = 4,
        RotatingRight = 8,
        BoostRotatingLeft = 16,
        BoostRotatingRight = 32,
        BoostAccelerating = 64,
        BoostReversingDirection = 128,
    }
    public static class EnumExtensions
    {
        public static bool HasFlag(this ShipState item, ShipState query)
        {
            return ((item & query) == query);
        }
    }

    public class Ship : DistributedSolidBody
    {
        public override void Draw(SpriteBatch batch)
        {
            throw new NotImplementedException();
        }

        private Storyboard storyboard = new Storyboard();
        private PositiveRecharger weaponRecharger = new PositiveRecharger(10000f, 10f);

        public ShipState State { get; set; }


        private Vector2 _velocity;
        public Vector2 Velocity
        {
            get { return _velocity; }
            protected set { if (this.MovementDampingEnabled) _velocity = value.Clamp(5); else _velocity = value; }
        }

        public Ship Target { get; set; }

        public float Acceleration { get; protected set; }
        public float Rotation { get; protected set; }

        private bool MovementDampingEnabled { get; set; }

        public int leftShield = 10, rightShield = 10, forwardShield = 10, backShield = 10, structure = 10;


        public Ship()
        {
            this.CollisionGroup = CollisionGroup.P1Ships;
            this.MovementDampingEnabled = true;
        }

        public void Accelerate()
        {
            this.State &= ~ShipState.Breaking;
            this.State |= ShipState.Accelerating;
        }

        public void Break()
        {
            this.State &= ~ShipState.Accelerating;
            this.State |= ShipState.Breaking;
        }

        public void BoostAccelerate()
        {
            this.State |= ShipState.BoostAccelerating;

            this.storyboard.Add(new FloatTimeline(f => this.Acceleration += f, this.Acceleration, this.Acceleration + 0.45f, 150f, 0, false, false, 0));

            this.storyboard.Add(new ActionTimeline(850f, delegate() { this.Break(); this.State &= ~ShipState.BoostAccelerating; }));
            this.storyboard.Add(new ActionTimeline(1450f, delegate() { this.MovementDampingEnabled = true; }));

            MovementDampingEnabled = false;
        }

        public void BoostReverseDirection()
        {
            this.State |= ShipState.BoostReversingDirection;

            this.storyboard.Add(new FloatTimeline(f => this.Rotation += f, 0, 0.1f, 600f, 0, false, true, 0));
            this.storyboard.Add(new ActionTimeline(1200f, delegate() { this.State &= ~ShipState.BoostReversingDirection; }));

        }

        public void RotateLeft()
        {
            this.State &= ~ShipState.RotatingRight;
            this.State |= ShipState.RotatingLeft;
        }

        public void RotateRight()
        {
            this.State &= ~ShipState.RotatingLeft;
            this.State |= ShipState.RotatingRight;
        }

        public void StopRotating()
        {
            this.State &= ~ShipState.RotatingRight & ~ShipState.RotatingLeft;
        }

        public void BoostRotatingLeft()
        {
            this.State |= ShipState.BoostRotatingLeft;

            storyboard.Add(new FloatTimeline(f => this.Rotation += f, 0, -0.1f, 300f, 0, false, true, 0));
            storyboard.Add(new ActionTimeline(600f, delegate() { this.Rotation = 0f; this.State &= ~ShipState.BoostRotatingLeft; }));
        }

        public void BoostRotatingRight()
        {
            this.State |= ShipState.BoostRotatingRight;

            storyboard.Add(new FloatTimeline(f => this.Rotation += f, 0, 0.1f, 300f, 0, false, true, 0));
            storyboard.Add(new ActionTimeline(600f, delegate() { this.Rotation = 0f; this.State &= ~ShipState.BoostRotatingRight; }));
        }

        public virtual Shot Fire()
        {
            if (this.weaponRecharger.TryDrain(3.0f))
            {
                Shot shot;

                shot = new Shot();
                shot.CollisionGroup = CollisionGroup.P1Shots;
                shot.Position = this.Position;
                
                shot.Velocity = this.Position.GetInterceptVector(Target.Position, this.Velocity, Target.Velocity, 6.5f);
                shot.Direction = shot.Velocity.GetAngle();

                //shot.Direction = (-this.Position.GetInterceptVector2(this.Velocity, 4f, this.Target.Position, this.Target.Velocity) + this.Position).GetAngle();
                //shot.Velocity = shot.Direction.GetNormalizedVector2() * 4f + this.Velocity;
                

                return shot;
            }
            return null;

        }

        public override void Update(GameTime gameTime)
        {
            DebuggerView.SetValue("Weapn recharger " + this.Key.ToString(), this.weaponRecharger.CurrentValue);

            if (this.State.HasFlag(ShipState.BoostAccelerating))
            { }
            else if (this.State.HasFlag(ShipState.Breaking))
            {
                this.Acceleration = 0f;
                this.Velocity = new Vector2()
                {
                    X = this.Velocity.X - 0.05f * this.Velocity.X,
                    Y = this.Velocity.Y - 0.05f * this.Velocity.Y
                };
            }
            else if (this.State.HasFlag(ShipState.Accelerating))
            {
                if (this.Acceleration < 0.1f)
                    this.Acceleration = 0.1f;
            }
            else
                this.Acceleration = 0f;

            if (this.State.HasFlag(ShipState.BoostReversingDirection) ||
                this.State.HasFlag(ShipState.BoostRotatingRight) ||
                this.State.HasFlag(ShipState.BoostRotatingLeft))
            { }
            else if (this.State.HasFlag(ShipState.RotatingRight))
                this.Rotation = 0.04f;
            else if (this.State.HasFlag(ShipState.RotatingLeft))
                this.Rotation = -0.04f;
            else
                this.Rotation = 0f;

            this.Velocity = this.Direction.GetNormalizedVector2() * this.Acceleration + this.Velocity;

            this.Body.Position = new Vector2()
                {
                    X = this.Body.Position.X + this.Velocity.X,
                    Y = this.Body.Position.Y + this.Velocity.Y
                };

            this.Body.Direction += this.Rotation;



            this.storyboard.Update(gameTime);
            this.weaponRecharger.Update(gameTime);

            this._DEBUG_IntersectingShapes.Clear();
        }

        public override void OnCollision(IBody obstacle, List<BodyShape> intersectingColliderShapes, List<BodyShape> intersectingObstacleShapes)
        {
            if (obstacle is Shot)
            {
                if (intersectingColliderShapes.Any(shape => shape.Name.Equals("left")))
                    TakeDamage("left");
                if (intersectingColliderShapes.Any(shape => shape.Name.Equals("right")))
                    TakeDamage("right");
                if (intersectingColliderShapes.Any(shape => shape.Name.Equals("forward")))
                    TakeDamage("forward");
                if (intersectingColliderShapes.Any(shape => shape.Name.Equals("back")))
                    TakeDamage("back");
            }

            this._DEBUG_IntersectingShapes.AddRange(intersectingColliderShapes);
        }

        private void TakeDamage(string shipPart)
        {
            switch (shipPart)
            {
                case ("left"): if (leftShield > 0) leftShield--; else structure--;
                    break;
                case ("right"): if (rightShield > 0) rightShield--; else structure--;
                    break;
                case ("forward"): if (forwardShield > 0) forwardShield--; else structure--;
                    break;
                case ("back"): if (backShield > 0) backShield--; else structure--;
                    break;
            }

        }

        public List<BodyShape> _DEBUG_IntersectingShapes = new List<BodyShape>();
    }

    public class AIShip : Ship
    {
        //public Ship Enemy { get; set; }
        public float Angle { get; set; }

        public AIShip()
        {
            this.CollisionGroup = CollisionGroup.A1Ships;
        }

        public override Shot Fire()
        {
            //return null;
            Shot shot = base.Fire();

            if (shot != null)
                shot.CollisionGroup = CollisionGroup.A1Shots;

            return shot;
        }

        public override void Update(GameTime gameTime)
        {
            #region AI Behavior update

            float alfa = this.Position.GetAngle(this.Target.Position);

            float dif = MathHelper.WrapAngle(alfa - this.Direction);
            Angle = MathHelper.ToDegrees(dif);

            if (dif > MathHelper.Pi / 12 && dif < MathHelper.Pi)
                this.RotateRight();
            else if (dif < MathHelper.Pi && dif < -MathHelper.Pi / 12)
                this.RotateLeft();
            else
                this.StopRotating();


            if ((this.Position - Target.Position).Length() > 500 && Math.Abs(dif) < MathHelper.Pi / 12)
                this.Accelerate();
            else
                this.Break();

            Timer.Run(this, gameTime, 500, delegate()
            {
                if ((this.Position - Target.Position).Length() < 600 && Math.Abs(dif) < MathHelper.Pi / 12)
                    Fire();
            });

            #endregion



            base.Update(gameTime);
        }
    }

    public class Shot : DistributedSolidBody
    {
        public Vector2 Velocity { get; set; }
        static public Texture2D SharedTexture;
        static public BodyShapeList ShapeList;
        private double? BeginLifeTime;
        private int frame;

       

        public Shot()
        {
            if (Shot.SharedTexture == null) throw new ArgumentNullException("Static Texture is null");

            this.Texture = Shot.SharedTexture;

            if (Shot.ShapeList == null) throw new ArgumentException("Static ShapeList is null");
            this.Body = new Body();
            this.Body.ShapeList = Shot.ShapeList;
            this.Body.Scale = new Vector2(0.45f, 0.25f);
            //this.Body.Origin = new Vector2(Shot.SharedTexture.Width / 2.0f / 6f, Shot.SharedTexture.Height / 2.0f / 6f);
            this.Body.Origin = new Vector2(Shot.SharedTexture.Width / 2.0f, Shot.SharedTexture.Height / 2.0f);

            Game1.shots.Add(this);
            Game1.sap.Add(this);
        }

        public override void Update(GameTime gameTime)
        {
            if (BeginLifeTime == null)
                BeginLifeTime = gameTime.TotalGameTime.TotalMilliseconds;

            if (gameTime.TotalGameTime.TotalMilliseconds - BeginLifeTime > 3000)
            {
                Game1.sap.Remove(this);
                Game1.shotsToRemove.Add(this);
                Explosion explosion = new Explosion(this.Position, this.Velocity);
            }

            this.Body.Position = new Vector2()
            {
                X = this.Body.Position.X + this.Velocity.X,
                Y = this.Body.Position.Y + this.Velocity.Y
            };
            frame = (frame + 1) % 36;
        }

        public override void OnCollision(IBody obstacle, List<BodyShape> intersectingColliderShapes, List<BodyShape> intersectingObstacleShapes)
        {
            Game1.sap.Remove(this);
            Game1.shotsToRemove.Add(this);
            Explosion explosion = new Explosion(this.Position, Vector2.Zero);

            explosion.Velocity = this.Velocity; // (obstacle as Ship).Velocity;

            if (obstacle is Ship)
            {
                explosion.Velocity = (obstacle as Ship).Velocity;
                Shield shield;
                shield = new Shield(obstacle as Ship);
            }

        }

        public override void Draw(SpriteBatch batch)
        {
            int x = frame % 6;
            int y = frame / 6;

            //batch.Draw(this.Texture, this.Position, new Rectangle(x * 128, y * 64, 128, 64), Color.Yellow,
            //        this.Direction, this.Body.Origin, this.Body.Scale, SpriteEffects.None, 0.0f);

            batch.Draw(this.Texture, this.Position, null, Color.White,
                    this.Direction, this.Body.Origin, this.Body.Scale, SpriteEffects.FlipHorizontally, 0.0f);
        }
    }


    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        VectorRenderer vectorRenderer;

        public static Ship ship;
        AIShip ship2;

        static public List<Shot> shots = new List<Shot>();
        static public List<Shot> shotsToRemove = new List<Shot>();

        static public List<Explosion> explosions = new List<Explosion>();
        static public List<Explosion> explosionsToRemove = new List<Explosion>();

        static public List<Shield> shields = new List<Shield>();
        static public List<Shield> shieldsToRemove = new List<Shield>();
        public RenderTarget2D lightMap;

        static public Sap sap = new Sap();
        static public GradientAnimator HUDShield_GradientAnimator = new GradientAnimator(new GradientStop(Color.Green, 0), new GradientStop(Color.Yellow, 0.5f), new GradientStop(Color.Red, 1.0f));



        List<BodyShape>[] list = new List<BodyShape>[2];

        Texture2D clouds, stars, alphaClearTexture;
        static public SpriteFont font;

        KeyboardInput keyboard;
        Storyboard storyboard;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            this.IsFixedTimeStep = false;

            sap.CollisionBinding.Add(CollisionGroup.A1Shots, CollisionGroup.P1Ships);
            sap.CollisionBinding.Add(CollisionGroup.P1Shots, CollisionGroup.A1Ships);

            this.storyboard = new Storyboard();
        }



        protected override void Initialize()
        {
            vectorRenderer = new VectorRenderer(this, Content, "Effects/LineDrawing");
            this.Components.Add(vectorRenderer);

            this.graphics.PreferredBackBufferWidth = 1680;
            this.graphics.PreferredBackBufferHeight = 1050;
            this.graphics.SynchronizeWithVerticalRetrace = true;
            this.graphics.ApplyChanges();
            graphics.ToggleFullScreen();
            this.keyboard = new KeyboardInput(Keyboard.GetState(), new Keys[] { Keys.W, Keys.A, Keys.D, Keys.Space, Keys.S, });



            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            clouds = Content.Load<Texture2D>("Textures/clouds23");
            stars = Content.Load<Texture2D>("Textures/t001stars");
            font = Content.Load<SpriteFont>("Font/Font");

            PresentationParameters pp = GraphicsDevice.PresentationParameters;

            lightMap = new RenderTarget2D(GraphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, 1, SurfaceFormat.Color, pp.MultiSampleType, pp.MultiSampleQuality);
            alphaClearTexture = Content.Load<Texture2D>("Textures/AlphaOne");



            #region Load ships
            XmlSerializer deserializer = new XmlSerializer(typeof(BodyShapeList));

            Stream reader = new FileStream("Bodies/ship1.xml", FileMode.Open);

            ship = new Ship();

            //ship.Texture = Content.Load<Texture2D>("Textures/Shuttle1");
            ship.Texture = Content.Load<Texture2D>("Textures/Warbird_smooth_blur");

            ship.Body = new Body();



            ship.Body.ShapeList = (BodyShapeList)deserializer.Deserialize(reader);
            reader.Close();
            ship.Body.Origin = new Vector2(ship.Texture.Width / 3.0f*2,
                                            ship.Texture.Height / 2.0f);
            ship.Body.Direction = 0;
            ship.Body.Scale = new Vector2(0.55f);


            ship2 = new AIShip();

            ship2.Texture = ship.Texture;
            ship2.Body = new Body();

            ship2.Body.ShapeList = ship.Body.ShapeList;
            ship2.Body.Origin = ship.Body.Origin;
            ship2.Body.Position = new Vector2(400, 400);
            ship2.Body.Scale = new Vector2(0.35f);


            #endregion

            Shot.SharedTexture = Content.Load<Texture2D>("Textures/laser");
            Shot.SharedTexture = Content.Load<Texture2D>("Textures/pulseShot");

            reader = new FileStream("Bodies/laserShot.xml", FileMode.Open);
            Shot.ShapeList = (BodyShapeList)deserializer.Deserialize(reader);
            reader.Close();

            Global.Load(Content);


            sap.Add(ship);
            sap.Add(ship2);

            ship.Target = ship2;
            ship2.Target = ship;
        }

        protected override void Update(GameTime gameTime)
        {

            //Timer.Run("Update.Main", gameTime, 16.6, delegate()
            //{
            #region Input

            if (keyboard.IsDown(Keys.D))
                ship.RotateRight();
            if (keyboard.IsDown(Keys.A))
                ship.RotateLeft();
            if (keyboard.IsDown(Keys.W))
                ship.Accelerate();
            if (keyboard.IsDown(Keys.S))
                ship.Break();

            if (keyboard.IsReleased(Keys.D))
                ship.State &= ~ShipState.RotatingRight;
            if (keyboard.IsReleased(Keys.A))
                ship.State &= ~ShipState.RotatingLeft;
            if (keyboard.IsReleased(Keys.W))
                ship.State &= ~ShipState.Accelerating;
            if (keyboard.IsReleased(Keys.S))
                ship.State &= ~ShipState.Breaking;


            if (keyboard.IsDoublePressed(Keys.W))
                ship.BoostAccelerate();
            if (keyboard.IsDoublePressed(Keys.A))
                ship.BoostRotatingLeft();
            if (keyboard.IsDoublePressed(Keys.D))
                ship.BoostRotatingRight();
            if (keyboard.IsDoublePressed(Keys.S))
                ship.BoostReverseDirection();



            if (keyboard.IsPressed(Keys.Space))
                ship.Fire();

            DebuggerView.SetValue("Ship Acceleration", ship.Acceleration);
            DebuggerView.SetValue("Ship Rotation", ship.Rotation);


            keyboard.Update(Keyboard.GetState(), gameTime);

            #endregion

            #region Update

            ship.Update(gameTime);
            this.ship2.Update(gameTime);


            foreach (var shot in shots)
                shot.Update(gameTime);

            foreach (var shot in shotsToRemove)
                shots.Remove(shot);

            shotsToRemove.Clear();

            storyboard.Update(gameTime);
            //});

            Timer.Run("Update.Animations", gameTime, 33.3, delegate()
             {

                 foreach (var exp in explosions)
                     exp.Update(gameTime);

                 foreach (var exp in explosionsToRemove)
                     explosions.Remove(exp);

                 explosionsToRemove.Clear();


                 foreach (var shield in shields)
                     shield.Update(gameTime);

                 foreach (var shield in shieldsToRemove)
                     shields.Remove(shield);

                 shieldsToRemove.Clear();
             });

            #endregion

            Timer.Run("Update.CollisionDetection", gameTime, 16.6, delegate()
            {
                sap.Update();
            });

            base.Update(gameTime);
        }

        private void DrawLightmap()
        {
            GraphicsDevice.SetRenderTarget(0, lightMap);

            GraphicsDevice.Clear(Color.Gray);

            //draw the light shape
            //where Alpha is 0, nothing will be written
            spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None, camera);
            GraphicsDevice.RenderState.DestinationBlend = Blend.One;
            GraphicsDevice.RenderState.SourceBlend = Blend.DestinationAlpha;
            GraphicsDevice.RenderState.BlendFunction = BlendFunction.Add;
            GraphicsDevice.RenderState.SeparateAlphaBlendEnabled = true;

            Vector2 lightPosition = new Vector2() { X = Mouse.GetState().X, Y = Mouse.GetState().Y };

            
            //spriteBatch.Draw(Global.SpriteSheets.LightGreenTrans.Texture, new Vector2(300, 350), Color.White);
            //spriteBatch.Draw(Global.SpriteSheets.LightGreen.Texture, new Vector2(350, 300), Color.White);

            foreach (var shot in shots)
                spriteBatch.Draw(Global.SpriteSheets.LightWhite.Texture, new Vector2(
                    (int)shot.Position.X,
                    (int)shot.Position.Y), null, new Color(0,120,0), 0f,
                    new Vector2(Global.SpriteSheets.LightWhite.Texture.Width / 2f, Global.SpriteSheets.LightWhite.Texture.Height / 2f), 1,
                     SpriteEffects.None, 0);

            foreach (var shot in shots)
                spriteBatch.Draw(Global.SpriteSheets.LightWhite.Texture, new Vector2(
                    (int)shot.Position.X,
                    (int)shot.Position.Y), null, new Color(0, 100, 0), 0f,
                    new Vector2(Global.SpriteSheets.LightWhite.Texture.Width / 2f, Global.SpriteSheets.LightWhite.Texture.Height / 2f), 0.5f,
                     SpriteEffects.None, 0);


            //spriteBatch.Draw(Global.SpriteSheets.LightWhiteReverse.Texture, lightPosition, Color.White);

            spriteBatch.End();


            GraphicsDevice.SetRenderTarget(0, null);
        }

        public static Matrix camera;

        protected override void Draw(GameTime gameTime)
        {
            camera = Matrix.CreateTranslation(new Vector3(-ship.Position.X / 2 + this.graphics.PreferredBackBufferWidth / 2, -ship.Position.Y / 2 + this.graphics.PreferredBackBufferHeight / 2, 0));
            camera = Matrix.CreateTranslation(new Vector3(
                -ship.Position.X + this.graphics.PreferredBackBufferWidth / 2,
                -ship.Position.Y + this.graphics.PreferredBackBufferHeight / 2, 0));

            DrawLightmap();

            GraphicsDevice.Clear(Color.Black);

            //Matrix camera;


            #region Draw Background & Ships & Shots

            camera = Matrix.CreateTranslation(new Vector3(-ship.Position.X / 2 + this.graphics.PreferredBackBufferWidth / 2, -ship.Position.Y / 2 + this.graphics.PreferredBackBufferHeight / 2, 0));
            
            
            int shipCameraX = ((int)ship.Position.X) / this.graphics.PreferredBackBufferWidth;
            int shipCameraY = ((int)ship.Position.Y) / this.graphics.PreferredBackBufferHeight;

            spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None, camera);
            for (int i = shipCameraX - 2; i < shipCameraX + 2; i++)
                for (int j = shipCameraY - 2; j < shipCameraY + 2; j++)
                {
                    spriteBatch.Draw(stars, new Rectangle(i * this.graphics.PreferredBackBufferWidth, j * this.graphics.PreferredBackBufferHeight, this.graphics.PreferredBackBufferWidth, this.graphics.PreferredBackBufferHeight), Color.White);

                }
            spriteBatch.End();


            camera = Matrix.CreateTranslation(new Vector3(
                -ship.Position.X + this.graphics.PreferredBackBufferWidth / 2,
                -ship.Position.Y + this.graphics.PreferredBackBufferHeight / 2, 0));


            spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None, camera);

            for (int i = shipCameraX - 2; i < shipCameraX + 2; i++)
                for (int j = shipCameraY - 2; j < shipCameraY + 2; j++)
                {
                    spriteBatch.Draw(clouds, new Rectangle(i * this.graphics.PreferredBackBufferWidth, j * this.graphics.PreferredBackBufferHeight, this.graphics.PreferredBackBufferWidth, this.graphics.PreferredBackBufferHeight), Color.White);

                }

            spriteBatch.Draw(

                ship.Texture,
                new Vector2(
                    (int)ship.Position.X,
                    (int)ship.Position.Y),
                null, Color.White,
                ship.Direction, ship.Body.Origin, ship.Body.Scale, SpriteEffects.FlipHorizontally, 0.0f);

            spriteBatch.Draw(

                this.ship2.Texture,
                new Vector2(
                    (int)this.ship2.Position.X,
                    (int)this.ship2.Position.Y),
                null, Color.Orange,
                this.ship2.Direction, ship2.Body.Origin, this.ship2.Body.Scale, SpriteEffects.FlipHorizontally, 0.0f);



            foreach (var shot in shots)
                shot.Draw(spriteBatch);

            foreach (var explosion in explosions)
                explosion.Draw(spriteBatch);

            foreach (var shield in shields)
                shield.Draw(spriteBatch);

            spriteBatch.End();

            #endregion

            spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None);

            DebuggerView.Draw(spriteBatch);

            HUDShield_GradientAnimator.Iterator = (10 - ship.forwardShield) / 10.0f;
            spriteBatch.Draw(
                Global.SpriteSheets.HudShieldPart.Texture,
                new Vector2(this.graphics.PreferredBackBufferWidth - 160, this.graphics.PreferredBackBufferHeight - 160),
                //new Vector2(300, 300),
                null, HUDShield_GradientAnimator.CurrentColor, // new Color(Color.White, ship.forwardShield / 10.0f),
                //0, Vector2.One,
                0, new Vector2(Global.SpriteSheets.HudShieldPart.Texture.Width / 2f, Global.SpriteSheets.HudShieldPart.Texture.Height + 8),
                1.0f, SpriteEffects.None, 0);

            HUDShield_GradientAnimator.Iterator = (10 - ship.rightShield) / 10.0f;
            spriteBatch.Draw(
                Global.SpriteSheets.HudShieldPart.Texture,
                new Vector2(this.graphics.PreferredBackBufferWidth - 160, this.graphics.PreferredBackBufferHeight - 160),
                //new Vector2(300, 300),
                null, HUDShield_GradientAnimator.CurrentColor,
                //0, Vector2.One,
                MathHelper.Pi / 2f, new Vector2(Global.SpriteSheets.HudShieldPart.Texture.Width / 2f, Global.SpriteSheets.HudShieldPart.Texture.Height + 8),
                1.0f, SpriteEffects.None, 0);

            HUDShield_GradientAnimator.Iterator = (10 - ship.backShield) / 10.0f;
            spriteBatch.Draw(
                Global.SpriteSheets.HudShieldPart.Texture,
                new Vector2(this.graphics.PreferredBackBufferWidth - 160, this.graphics.PreferredBackBufferHeight - 160),
                //new Vector2(300, 300),
                null, HUDShield_GradientAnimator.CurrentColor,
                //0, Vector2.One,
                MathHelper.Pi, new Vector2(Global.SpriteSheets.HudShieldPart.Texture.Width / 2f, Global.SpriteSheets.HudShieldPart.Texture.Height + 8),
                1.0f, SpriteEffects.None, 0);

            HUDShield_GradientAnimator.Iterator = (10 - ship.leftShield) / 10.0f;
            spriteBatch.Draw(
                Global.SpriteSheets.HudShieldPart.Texture,
                new Vector2(this.graphics.PreferredBackBufferWidth - 160, this.graphics.PreferredBackBufferHeight - 160),
                //new Vector2(300, 300),
                null, HUDShield_GradientAnimator.CurrentColor,
                //0, Vector2.One,
                -MathHelper.Pi / 2, new Vector2(Global.SpriteSheets.HudShieldPart.Texture.Width / 2f, Global.SpriteSheets.HudShieldPart.Texture.Height + 8),
                1.0f, SpriteEffects.None, 0);

            spriteBatch.End();


            //multiply scene with lightmap
            spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None);
            {
                GraphicsDevice.RenderState.SourceBlend = Blend.DestinationColor;
                GraphicsDevice.RenderState.DestinationBlend = Blend.SourceColor;
                spriteBatch.Draw(lightMap.GetTexture(), Vector2.Zero, Color.White);
            }
            spriteBatch.End();

            base.Draw(gameTime);
        }

        protected override void UnloadContent()
        {
        }
    }
}
